#include "Bsp_can.h"

#include "uds_port.h"

#include <stdint.h>

// clang-format off
USR_GPIO_Init can_ctl_pin[] = {
    [CAN_RX] = {GPIOA, {FL_GPIO_PIN_6, FL_GPIO_MODE_DIGITAL, FL_GPIO_OUTPUT_PUSHPULL, FL_ENABLE, FL_DISABLE, FL_DISABLE}},
    [CAN_TX] = {GPIOA, {FL_GPIO_PIN_7, FL_GPIO_MODE_DIGITAL, FL_GPIO_OUTPUT_PUSHPULL, FL_ENABLE, FL_DISABLE, FL_DISABLE}},
    //[CAN_STB ]= {GPIOD,{FL_GPIO_PIN_11 ,FL_GPIO_MODE_OUTPUT,FL_GPIO_OUTPUT_PUSHPULL,FL_DISABLE,FL_DISABLE,FL_DISABLE}},
    [CAN_STB] = {GPIOC, {FL_GPIO_PIN_10, FL_GPIO_MODE_OUTPUT, FL_GPIO_OUTPUT_PUSHPULL, FL_DISABLE, FL_DISABLE, FL_DISABLE}},

};
// clang-format on

CAN_Queue_t can_send_queue;
CAN_Frame_t can_send_buffer[CAN_MSG_BUFFER_SIZE];
CAN_Queue_t can_recv_queue;
CAN_Frame_t can_recv_buffer[CAN_MSG_BUFFER_SIZE];

uint8_t  Bus_Off_Flag       = 0;
uint8_t  Fast_Recover_Count = 5;
uint32_t Recover_Timeout    = FAST_RECOVER_TIMEOUT; /* 初始为快恢复 */

/**
 * @brief  CAN中断函数
 * @param  void
 * @retval void
 */
void CAN_IRQHandler(void)
{
    CAN_Frame_t volatile msg_data;
    if ((FL_ENABLE == FL_CAN_IsEnabledIT_RXOK(CAN)) && (FL_SET == FL_CAN_IsActiveFlag_RXOK(CAN))) {
        msg_data.std_id       = FL_CAN_ReadRXMessageID(CAN);
        msg_data.dlc          = FL_CAN_ReadRXMessageLength(CAN);
        msg_data.data.word[0] = FL_CAN_ReadRXMessageWord1(CAN);
        msg_data.data.word[1] = FL_CAN_ReadRXMessageWord2(CAN);

        // TODO 1. 接收补偿点初始值a
        if (msg_data.std_id == COMPENSTAION_ID && msg_data.dlc == 2) {
            // 初始值a一定是2个字节内的数据, 所以只需要接收word1, 因为传输的是电导值，所以需要用1e6除
            if ((msg_data.data.word[0] & 0xffff) != 0) {
                compensation.initialValue = 1.0 * 1e6 / (msg_data.data.word[0] & 0xffff);
                is_recv_comp_init_val     = true;
            }
        }
        /* 接收到擦除补偿系数ID */
        else if (msg_data.std_id == ERASURE_ID && msg_data.dlc == 1) {
            is_recv_erasure_flash = true;
        }

        // TODO:入队列
        uds_recv_frame(msg_data.std_id, msg_data.data.byte, msg_data.dlc);
        FL_CAN_ClearFlag_RXOK(CAN);
    }

    if (FL_CAN_IsActiveFlag_Error(CAN) && FL_CAN_IsEnabledIT_Error(CAN)) {
        FL_CAN_ClearFlag_Error(CAN);
    }

    if (FL_CAN_IsActiveFlag_BusOff(CAN) && FL_CAN_IsEnabledIT_BusOff(CAN)) {
        FL_CAN_SetSoftwareReset(CAN, FL_CAN_SOFTWARE_RESET);
        Bus_Off_Flag = 1;
        FL_CAN_ClearFlag_BusOff(CAN);
    }

    if (FL_CAN_IsActiveFlag_TXOK(CAN) && FL_CAN_IsEnabledIT_TXOK(CAN)) {
        Bus_Off_Flag = 0;
        FL_CAN_ClearFlag_TXOK(CAN);
        /* 退出BUSOFF后，清零计数器 */
        Fast_Recover_Count = 5;
        Recover_Timeout    = FAST_RECOVER_TIMEOUT;
    }
}

void Bsp_CAN_GPIO_init(void)
{
    int i = 0;
    for (i = 0; i < (sizeof(can_ctl_pin) / sizeof(can_ctl_pin[0])); i++) {
        FL_GPIO_Init(can_ctl_pin[i].GPIOx, &can_ctl_pin[i].init_type);
    }
    FL_GPIO_ResetOutputPin(can_ctl_pin[CAN_STB].GPIOx, can_ctl_pin[CAN_STB].init_type.pin);

    FIFO_QueueInit(&can_send_queue, can_send_buffer, CAN_MSG_BUFFER_SIZE);
}

void Module_CAN_init(uint16_t filter_id)
{
    FL_CAN_InitTypeDef       CAN_InitStruct;
    FL_CAN_FilterInitTypeDef Filter_InitStruct;

    CAN->CR                    = 0;
    CAN_InitStruct.mode        = FL_CAN_MODE_NORMAL;
    CAN_InitStruct.SJW         = FL_CAN_SJW_1Tq;
    CAN_InitStruct.TS1         = FL_CAN_TS1_12Tq;
    CAN_InitStruct.TS2         = FL_CAN_TS2_3Tq;
    CAN_InitStruct.BRP         = 0;
    CAN_InitStruct.clockSource = FL_CMU_CAN_CLK_SOURCE_XTHF;

    FL_CAN_Init(CAN, &CAN_InitStruct);

    Filter_InitStruct.filterIdSRR      = FL_CAN_SRR_BIT_LOW;
    Filter_InitStruct.filterIdIDE      = FL_CAN_IDE_BIT_LOW;
    Filter_InitStruct.filterIdRTR      = FL_CAN_RTR_BIT_LOW;
    Filter_InitStruct.filterIdStandard = 0x700;
    Filter_InitStruct.filterIdExtend   = 0x00;
    Filter_InitStruct.filterMaskIdHigh = 0X7FF;
    Filter_InitStruct.filterMaskIdLow  = 0; // 0X3FFFF;

    Filter_InitStruct.filterMaskIdSRR = FL_ENABLE;
    Filter_InitStruct.filterMaskIdIDE = FL_ENABLE;
    Filter_InitStruct.filterMaskIdRTR = FL_ENABLE;
    Filter_InitStruct.filterEn        = FL_ENABLE;

    // 过滤ID需要根据当前ID选择
    filter_id += DIAG_ID_BASE;
    Filter_InitStruct.filterIdStandard = filter_id & 0X7FF;
    FL_CAN_FilterInit(CAN, &Filter_InitStruct, FL_CAN_FILTER1);

    // 诊断ID所有节点通用
    Filter_InitStruct.filterIdStandard = FUNCTION_ID;
    FL_CAN_FilterInit(CAN, &Filter_InitStruct, FL_CAN_FILTER2);
}

/**
 * @brief  CAN Interrupt Initialization function
 * @param  void
 * @retval None
 */
void MF_CAN_Interrupt_Init(void)
{
    FL_CAN_ClearFlag_RXOK(CAN);
    FL_CAN_EnableIT_RXOK(CAN); /* 接收中断使能 */

    // FL_CAN_ClearFlag_RXNotEmpty(CAN);
    // FL_CAN_EnableIT_RXNotEmpty(CAN);

    FL_CAN_ClearFlag_Error(CAN);
    FL_CAN_EnableIT_Error(CAN);    /* 错误中断使能 */

    FL_CAN_ClearFlag_BusOff(CAN);
    FL_CAN_EnableIT_BusOff(CAN);   /* BusOff中断使能 */

    FL_CAN_ClearFlag_TXOK(CAN);
    FL_CAN_EnableIT_TXOK(CAN);     /* 发送完成中断使能 */

    NVIC_DisableIRQ(CAN_IRQn);
    NVIC_SetPriority(CAN_IRQn, 2); /* 中断优先级配置 */
    NVIC_EnableIRQ(CAN_IRQn);
}

bool Bsp_get_CAN_Tx_Ready()
{
    // XXX:状态查询需考虑流控等因素
    bool ret = false;

#if 0 // 阻塞式查询严重影响性能，故更改为查询调度式
//状态标志为0时，才能清0中断标志
    do {
        buffstatus = FL_CAN_IsActiveFlag_TXBuffFullSignal(CAN);
        counter++;
    } while((buffstatus != 0U) && (counter != CAN_TIMEOUT));
#endif
    if (0 != Bus_Off_Flag) {
        return false;
    }
    if (0 != FL_CAN_IsActiveFlag_TXBuffFullSignal(CAN)) {
        return false;
    }

    (void)ret;
    return true;
}
void Bsp_CAN_FIFO_Write(uint32_t id, uint8_t len, uint8_t *dat)
{
    uint32_t data1 = 0;
    uint32_t data2 = 0;
    len            = 8;

    data1 = (((uint32_t)dat[3] << 24) | ((uint32_t)dat[2] << 16) | ((uint32_t)dat[1] << 8) |
             ((uint32_t)dat[0]));
    data2 = (((uint32_t)dat[7] << 24) | ((uint32_t)dat[6] << 16) | ((uint32_t)dat[5] << 8) |
             ((uint32_t)dat[4]));

    // FL_CAN_FIFO_Write(id, len, data1, data2);

    FL_CAN_ClearFlag_TXBuffFull(CAN);
    FL_CAN_WriteTXMessageID(CAN, id);
    FL_CAN_WriteTXMessageLength(CAN, len);
    FL_CAN_WriteTXMessageWord1(CAN, data1);
    FL_CAN_WriteTXMessageWord2(CAN, data2);
}

CAN_Frame_t busoff_can_frame = {
    .data.word[0] = 0X01020304,
    .data.word[1] = 0X05060708,
};
// TODO:1ms周期调用
void CAN_busoff_handle(void)
{
    if (Bus_Off_Flag) {
        if (--Recover_Timeout == 0) {
            Bus_Off_Flag = 0;

            if (Fast_Recover_Count) {
                Fast_Recover_Count--;
            }

            if (Fast_Recover_Count == 0) {
                Recover_Timeout = SLOW_RECOVER_TIMEOUT;
            }
            else {
                Recover_Timeout = FAST_RECOVER_TIMEOUT;
            }
            // 重新初始化
            Module_CAN_init(Dev_GetNodeID());
            MF_CAN_Interrupt_Init();
            // 发送数据
            Bsp_CAN_FIFO_Write(0x6AD, 8, busoff_can_frame.data.byte);
        }
    }
}

void BSp_CAN_init(void)
{
    /* Initial CAN */
    Bsp_CAN_GPIO_init();
    Module_CAN_init(Dev_GetNodeID());
    MF_CAN_Interrupt_Init();
}
